package com.ease.script.rhino;

import java.util.Collection;
import java.util.Map;

import javax.script.Bindings;
import javax.script.SimpleBindings;

import com.ease.common.util.Detect;

/**
 * 
 * @author nathanleewei
 * 
 */
public class NestedBindings extends SimpleBindings {

	protected Bindings nested;

	public NestedBindings() {

	}

	public NestedBindings(Bindings nested) {
		this.setNested(nested);
	}

	protected void checkKey(Object key) {
		if (key == null) {
			throw new NullPointerException("key can not be null");
		}
		if (!(key instanceof String)) {
			throw new ClassCastException("key should be a String");
		}
		if (key.equals("")) {
			throw new IllegalArgumentException("key can not be empty");
		}
	}

	public void clear() {
		super.clear();
		if (null != nested) {
			nested.clear();
		}
	}

	/**
	 * @param key
	 * @return
	 * @see javax.script.Bindings#containsKey(java.lang.Object)
	 */
	public boolean containsKey(Object key) {
		boolean b = super.containsKey(key);
		if (false == b && null != nested) {
			b = nested.containsKey(key);
		}
		return b;
	}

	/**
	 * @param value
	 * @return
	 * @see java.util.Map#containsValue(java.lang.Object)
	 */
	public boolean containsValue(Object value) {
		boolean b = super.containsValue(value);
		if (false == b && null != nested) {
			b = nested.containsValue(value);
		}
		return b;
	}

	/**
	 * @param key
	 * @return
	 * @see javax.script.Bindings#get(java.lang.Object)
	 */
	public Object get(Object key) {
		if (super.containsKey(key)) {
			return super.get(key);
		}
		if (null != nested) {
			return nested.get(key);
		}
		return null;
	}

	/**
	 * @return
	 * @see java.util.Map#isEmpty()
	 */
	public boolean isEmpty() {
		return super.isEmpty() && (((null != nested)) ? nested.isEmpty() : true);
	}

	/**
	 * @param name
	 * @param value
	 * @return
	 * @see javax.script.Bindings#put(java.lang.String, java.lang.Object)
	 */
	public Object put(String name, Object value) {
		return super.put(name, value);
	}

	/**
	 * @param toMerge
	 * @see javax.script.Bindings#putAll(java.util.Map)
	 */
	public void putAll(Map<? extends String, ? extends Object> toMerge) {
		super.putAll(toMerge);
	}

	/**
	 * @param key
	 * @return
	 * @see javax.script.Bindings#remove(java.lang.Object)
	 */
	public Object remove(Object key) {
		return super.remove(key);
	}

	/**
	 * @return
	 * @see java.util.Map#size()
	 */
	public int size() {
		return super.size() + ((null != nested) ? nested.size() : 0);
	}

	/**
	 * @return
	 * @see java.util.Map#values()
	 */
	@SuppressWarnings("unchecked")
	public Collection<Object> values() {
		return Detect.union(super.values(), ((null != nested) ? nested.values() : null));
	}

	/**
	 * @return the nested
	 */
	public Bindings getNested() {
		return nested;
	}

	/**
	 * @param nested
	 *            the nested to set
	 */
	public void setNested(Bindings nested) {
		this.nested = nested;
	}

}
